//******************************************************************************/

#include "esp32_oled.hpp"
#include "stdlib.h"

#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "sys/unistd.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

static spi_device_handle_t spi;

void oledSpiInit(void)
{
    esp_err_t ret;

    esp_rom_gpio_pad_select_gpio(PIN_OLED_CS);                // 选择一个GPIO
    gpio_set_direction(PIN_OLED_CS, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出

    esp_rom_gpio_pad_select_gpio(PIN_OLED_DC);                // 选择一个GPIO
    gpio_set_direction(PIN_OLED_DC, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出

    esp_rom_gpio_pad_select_gpio(PIN_OLED_RES);                // 选择一个GPIO
    gpio_set_direction(PIN_OLED_RES, GPIO_MODE_OUTPUT);// 把这个GPIO作为输出

    spi_bus_config_t buscfg;
    memset(&buscfg, 0, sizeof(spi_bus_config_t));
    buscfg.miso_io_num = -1; // MISO信号线，可复用为QSPI的D0
    buscfg.mosi_io_num = PIN_OLED_DIN; // MOSI信号线，可复用为QSPI的D1
    buscfg.sclk_io_num = PIN_OLED_CLK; // SCLK信号线
    buscfg.quadwp_io_num = -1; // WP信号线，专用于QSPI的D2
    buscfg.quadhd_io_num = -1; // HD信号线，专用于QSPI的D3
    buscfg.max_transfer_sz = 4094; // 最大传输数据大小，单位字节，默认为4094

    // 对于ESP32 超过26Mhz会报错，C系列、S系列未知
    spi_device_interface_config_t devcfg;
    memset(&devcfg, 0, sizeof(spi_device_interface_config_t));
    devcfg.clock_speed_hz = SPI_MASTER_FREQ_26M;
    devcfg.mode = 0;
    devcfg.spics_io_num = -1;
    devcfg.queue_size = 6;

    // Initialize the SPI bus
    ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
}

uint8_t u8x8_byte_hard_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
    spi_transaction_t spi_trans;
    esp_err_t ret;
    // static uint8_t buf[128];
    // static uint8_t buf_idx;

    // printf("msg:%d,arg_int:%d\r\n",msg,arg_int);
    switch(msg){
     case U8X8_MSG_BYTE_SEND: /*通过SPI发送arg_int个字节数据*/
     {
         memset(&spi_trans, 0, sizeof(spi_trans));       // Zero out the transaction
         spi_trans.length = arg_int * 8;                 // Len is in bytes, transaction length is in bits.
         spi_trans.tx_buffer = arg_ptr;               // Data
         spi_trans.user = (void*)1;                // D/C needs to be set to 1
         ret = spi_device_polling_transmit(spi, &spi_trans);  // Transmit!
         assert(ret == ESP_OK);
     }
        break;
    case U8X8_MSG_BYTE_INIT: /*初始化函数*/
        // oled_spi_init();
        break;
    case U8X8_MSG_BYTE_SET_DC:
        arg_int == 1 ? OLED_DC_Set() : OLED_DC_Clr();
        // esp_rom_delay_us(1);
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        OLED_CS_Clr();
        // esp_rom_delay_us(1);
        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        OLED_CS_Set();
        // esp_rom_delay_us(1);
        break;
    default:
        return 0;
    }
    return 1;
}

uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    // 采用硬件spi，部分分支可以忽略不写
    switch (msg)
    {
    // Initialize SPI peripheral
    case U8X8_MSG_GPIO_AND_DELAY_INIT:
        break;
    // Function which implements a delay, arg_int contains the amount of ms
    case U8X8_MSG_DELAY_MILLI:
        // vTaskDelay(pdMS_TO_TICKS(arg_int));
        break;
    // Function which delays 10us
    case U8X8_MSG_DELAY_10MICRO:
        // esp_rom_delay_us(10);
        break;
    // Function to define the logic level of the CS line
    case U8X8_MSG_GPIO_CS:
        // arg_int == 1 ? OLED_CS_Set() : OLED_CS_Clr();
        break;
    // Function to define the logic level of the Data/ Command line
    case U8X8_MSG_GPIO_DC:
        // arg_int == 1 ? OLED_DC_Set() : OLED_DC_Clr();
        break;
    // Function to define the logic level of the RESET line
    case U8X8_MSG_GPIO_RESET:
        break;
    default:
        return 0; // A message was received which is not implemented, return 0 to indicate an error
    }
    return 1;
}

void oledReset(void)
{
    OLED_REST_Set();
    vTaskDelay(50 / portTICK_PERIOD_MS);
    OLED_REST_Clr();
    vTaskDelay(5 / portTICK_PERIOD_MS);
    OLED_REST_Set();
    vTaskDelay(50 / portTICK_PERIOD_MS);
}

void u8g2Init(u8g2_t *u8g2)
{
    u8g2_Setup_ssd1306_64x48_er_f(u8g2, U8G2_R0, u8x8_byte_hard_spi, u8x8_gpio_and_delay);
    u8g2_InitDisplay(u8g2);
    u8g2_SetPowerSave(u8g2, 0);
    u8g2_ClearBuffer(u8g2);
}




















